import time
from contextlib import asynccontextmanager
from typing import AsyncIterator

from sqlalchemy import inspect
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlmodel import SQLModel

from app.config import DatabaseType, settings
from app.utils.decorators.singleton import singleton


@singleton
class DatabaseFactory:
    """多数据库支持的工厂类"""

    def __init__(self):
        self._engines = {}
        self._session_makers = {}

    async def get_engine(self, db_type: DatabaseType = None):
        """获取数据库引擎"""
        db_type = db_type or settings.DB_TYPE
        if db_type not in self._engines:
            engine = create_async_engine(
                url=settings.db_url,
                echo=settings.DB_ECHO,  # 打印 SQL 日志，开发用 True，生产用 False
                future=True,  # 启用 2.0 API，始终 True（尤其是异步项目）
                max_overflow=settings.DB_MAX_OVERFLOW,  # 临时连接数，一般为 pool_size 的 50%~100%
                pool_size=settings.DB_POOL_SIZE,  # 空闲连接数，根据并发量调整
                pool_pre_ping=True,  # 自动检测失效连接，# 生产环境建议启用
                pool_recycle=3600,  # 1 小时后强制回收连接，pool_pre_ping的替代方案，强制定期重建连接
                pool_use_lifo=True,  # 使用LIFO策略可以提高连接池性能
            )
            self._engines[db_type] = engine

        return self._engines[db_type]

    async def get_session_maker(self, db_type: DatabaseType = None):
        """获取会话工厂"""
        db_type = db_type or settings.DB_TYPE
        if db_type not in self._session_makers:
            engine = await self.get_engine(db_type)
            session_maker = async_sessionmaker(
                bind=engine, expire_on_commit=False, autocommit=False, autoflush=False
            )
            self._session_makers[db_type] = session_maker

        return self._session_makers[db_type]

    async def init_db(self, db_type: DatabaseType = None):
        """初始化数据库"""
        db_type = db_type or settings.DB_TYPE
        engine = await self.get_engine(db_type)

        async with engine.begin() as conn:
            # 检查表是否已存在
            inspector = await conn.run_sync(lambda i: inspect(i))
            existing_tables = await conn.run_sync(lambda i: inspector.get_table_names())
            if not existing_tables:
                print("{0:-^100}".format("数据库初始化开始"))
                start_time = time.time()
                # 创建所有表
                await conn.run_sync(SQLModel.metadata.create_all)
                elapsed = time.time() - start_time
                print("{0:-^100}".format(f"数据库初始化完成，耗时: {elapsed:.2f}秒"))
            else:
                print("{0:-^100}".format("数据库表已存在，跳过初始化"))

    async def close(self):
        """关闭所有数据库连接"""
        for engine in self._engines.values():
            await engine.dispose()
        self._engines.clear()
        self._session_makers.clear()
        print("{0:-^100}".format(f"数据库连接已关闭"))


@asynccontextmanager
async def get_async_context_manager() -> AsyncIterator[AsyncSession]:
    """每个请求创建独立session，请求结束时自动关闭"""
    session_maker = await DatabaseFactory().get_session_maker()
    async with session_maker() as session:
        try:
            yield session
        except Exception as e:
            await session.rollback() # 异常时回滚
            raise e
        finally:
            await session.close() # 确保连接归还连接池